home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / c / cc02.zip / DIFF.C < prev    next >
Text File  |  1985-05-09  |  7KB  |  366 lines

  1. /*
  2.  *    diff.c ->    Source file comparator
  3.  *
  4.  *    Conforms to conventions of standard Unix library with the exception
  5.  *     of movmem()
  6.  */
  7.  
  8. /*
  9. To paraphrase the Unix (trademark Bell Laboratories) manual:
  10.  
  11. NAME
  12.      diff - differential file comparator
  13.  
  14. SYNOPSIS
  15.      diff file1 file2
  16.  
  17. DESCRIPTION
  18.      Diff  tells  which  lines differ between  two  files.   Diff
  19.      outputs  to the standard output all affected lines from  the
  20.      first file preceeded by '<',  a line containing three dashes
  21.      ("---"),  then  all  affected  lines from  the  second  file
  22.      preceeded by '>'.
  23.  
  24.      Diff maintains a "synchronization window" of 50  lines,  and
  25.      generates an error message if the input files differ by more
  26.      than 50 lines.   Error messages are written to the  standard
  27.      error output.
  28.  
  29.      Diff ignores all carriage-return characters (0x0D),  so that
  30.      a    missing  carriage-return is not considered to be  a  dif-
  31.      ference.    For  backward compatability,  diff does recognize
  32.      control-Z (0x1A) as the end-of-file marker.
  33.  
  34. DIAGNOSTICS
  35.      Exit  status  is 0 for no differences,  1 for  some,  2  for
  36.      trouble.
  37.  */
  38.  
  39. #include <stdio.h>
  40.  
  41. #define EOFCHR        0x1A
  42. #define MAXLINES    50
  43. #define BUFFSIZ     (MAXLINES * 128)
  44.  
  45. typedef struct
  46. {
  47.     char    *lptr;        /*  -> text line in memory    */
  48.     int    lhash;        /*  hash of line's contents     */
  49. }
  50. LBUF;
  51.  
  52. typedef struct
  53. {
  54.     int    fd;        /*  file descriptor        */
  55.     char    *eptr,        /*  ptrs into buffer        */
  56.     *mptr;
  57.     char    buff[BUFFSIZ];    /*  the buffer            */
  58.     LBUF    line[MAXLINES]; /*  the lines            */
  59. }
  60. FBUF;
  61.  
  62. FBUF    *f1,            /*  the input files        */
  63. *f2;
  64.  
  65. int    differences = 0;    /*  found differences ??    */
  66.  
  67. extern char    *malloc();
  68.  
  69. /*
  70.  *    MatchLines() -> compare two lines for a match
  71.  */
  72.  
  73. int MatchLines(lev1, lev2)
  74. int    lev1,
  75. lev2;
  76. {
  77.     return ((f1->line[lev1].lhash == f2->line[lev2].lhash) &&
  78.         !strcmp(f1->line[lev1].lptr, f2->line[lev2].lptr));
  79. }
  80.  
  81. /*
  82.  *    Fatal() ->    fatal error
  83.  */
  84.  
  85. Fatal(mesg, arg)
  86. char    *mesg,
  87. *arg;
  88. {
  89.  
  90.     perror( mesg, arg );
  91.     exit( 2 );
  92.     /*
  93.  * orig lines
  94.  *    fprintf(stderr, "diff : ");
  95.  *    fprintf(stderr, mesg, arg);
  96.  *    fprintf(stderr, "\r\n");
  97.  *    exit(2);
  98.  */
  99. }
  100.  
  101. /*
  102.  *    ReadMore() ->    read in more lines, preserving lines in use
  103.  */
  104.  
  105. char *ReadMore(fdesc, last)
  106. FBUF    *fdesc;
  107. int    last;
  108. {
  109.     LBUF    *slin,
  110.     *elin;
  111.     int    size,
  112.     dist,
  113.     ramt;
  114.  
  115.     size = fdesc->mptr - fdesc->line[0].lptr;
  116.  
  117.     /*  move text to beginning of buffer  */
  118.     movmem(fdesc->line[0].lptr, fdesc->buff, size);
  119.     slin = fdesc->line;
  120.     elin = &fdesc->line[last];
  121.     dist = fdesc->line[0].lptr - fdesc->buff;
  122.  
  123.     /*  fix up existing line pointers  */
  124.     while (slin <= elin)
  125.     {
  126.         slin->lptr -= dist;
  127.         ++slin;
  128.     }
  129.  
  130.     /*  read in some more  */
  131.     ramt = read(fdesc->fd, fdesc->mptr - dist, size = (BUFFSIZ - size));
  132.     if (ramt < 0)
  133.         Fatal("file read error");
  134.  
  135.     fdesc->mptr += (ramt - dist);
  136.  
  137.     /*  check for EOF  */
  138.     if (ramt < size)
  139.         *fdesc->mptr = EOFCHR;
  140.  
  141.     return (fdesc->mptr - ramt);
  142. }
  143.  
  144. /*
  145.  *    HashMore() ->    read/hash a number of lines of text
  146.  */
  147.  
  148. HashMore(file, amt)
  149. int    file,
  150. amt;
  151. {
  152.     FBUF    *fdesc;
  153.     int    thash;
  154.     char    *cptr;
  155.  
  156.     for (fdesc = (file ? f2 : f1); amt > 0; --amt)
  157.     {
  158.         fdesc->line[MAXLINES - amt].lptr = cptr = fdesc->eptr;
  159.  
  160.         /*  check for EOF  */
  161.         if (!cptr)
  162.             fdesc->line[MAXLINES - amt].lhash = 0;
  163.         else
  164.         {
  165.             /*  calculate hash value  */
  166.             thash = 0;
  167.             for (;;)
  168.             {
  169.                 /*  don't use up the buffer  */
  170.                 if (cptr >= fdesc->mptr)
  171.                     cptr = ReadMore(fdesc, MAXLINES - amt);
  172.  
  173.                 if ((*cptr == EOFCHR) || (*cptr == '\n'))
  174.                     break;
  175.  
  176.                 if (*cptr == '\r')      /*  ignore CRs  */
  177.                     ++cptr;
  178.                 else
  179.                     thash += *cptr++;
  180.             }
  181.  
  182.             /*  terminate line correctly  */
  183.             if (*cptr == EOFCHR)
  184.             {
  185.                 *cptr = 0;
  186.                 cptr = NULL;
  187.             }
  188.             else
  189.                 *cptr++ = 0;
  190.  
  191.             /*  save the hash value  */
  192.             fdesc->line[MAXLINES - amt].lhash = thash;
  193.         }
  194.  
  195.         fdesc->eptr = cptr;
  196.     }
  197. }
  198.  
  199. /*
  200.  *    MoveDown() ->    move down a number of lines in each file
  201.  */
  202.  
  203. MoveDown(amt1, amt2)
  204. int    amt1,
  205. amt2;
  206. {
  207.     movmem(&f1->line[amt1], &f1->line[0],
  208.     sizeof(LBUF) * (MAXLINES - amt1));
  209.     HashMore(0, amt1);
  210.  
  211.     movmem(&f2->line[amt2], &f2->line[0],
  212.     sizeof(LBUF) * (MAXLINES - amt2));
  213.     HashMore(1, amt2);
  214. }
  215.  
  216. /*
  217.  *    PrintLine() ->    print the specified line
  218.  */
  219.  
  220. PrintLine(file, lev)
  221. int    file,
  222. lev;
  223. {
  224.     FBUF    *fdesc;
  225.  
  226.     fdesc = (file ? f2 : f1);
  227.  
  228.     printf("%c %s\r\n", (file ? '>' : '<'), fdesc->line[lev].lptr);
  229. }
  230.  
  231. /*
  232.  *    AtEOF() ->    check for both files at EOF
  233.  */
  234.  
  235. int AtEOF()
  236. {
  237.     return (!f1->line[0].lptr && !f2->line[0].lptr);
  238. }
  239.  
  240. /*
  241.  *    CloseUp() ->    close the files
  242.  */
  243.  
  244. CloseUp()
  245. {
  246.     close(f1->fd);
  247.     free(f1);
  248.     close(f2->fd);
  249.     free(f2);
  250. }
  251.  
  252. /*
  253.  *    CmpRegion() ->    compare a region
  254.  */
  255.  
  256. CmpRegion()
  257. {
  258.     int    depth,
  259.     level,
  260.     tmp;
  261.  
  262.     /*  move over matching portion    */
  263.     while (!AtEOF() && MatchLines(0, 0))
  264.         MoveDown(1, 1);
  265.  
  266.     if (AtEOF())
  267.         return;
  268.     else
  269.         differences = 1;
  270.  
  271.     /*  for each line in each file, compare it and next line with
  272.      *    every previous line in the other file, looking for a
  273.      *    two line match
  274.      */
  275.     depth = level = 0;
  276.     for (;;)
  277.     {
  278.         if (depth >= (MAXLINES - 1))
  279.             Fatal("files differ by more than %d lines", MAXLINES);
  280.  
  281.         if (MatchLines(level, depth) && MatchLines(level + 1, depth + 1))
  282.             break;
  283.         if (MatchLines(depth, level) && MatchLines(depth + 1, level + 1))
  284.             break;
  285.  
  286.         if (level < depth)
  287.             ++level;
  288.         else
  289.         {
  290.             ++depth;
  291.             level = 0;
  292.         }
  293.     }
  294.  
  295.     /*  make tmp be the length in the first file  */
  296.     if (MatchLines(level, depth) && MatchLines(level + 1, depth + 1))
  297.     {
  298.         tmp = level;
  299.         level = depth;
  300.         depth = tmp;
  301.     }
  302.  
  303.     /*  print the region of difference  */
  304.     tmp = 0;
  305.     while (tmp < depth)
  306.         PrintLine(0, tmp++);
  307.     printf("---\r\n");
  308.     tmp = 0;
  309.     while (tmp < level)
  310.         PrintLine(1, tmp++);
  311.  
  312.     MoveDown(depth, level);
  313. }
  314.  
  315. /*
  316.  *    Init() ->    initialize the input files
  317.  */
  318.  
  319. Init(name1, name2)
  320. char    *name1,
  321. *name2;
  322. {
  323.     if (!(f1 = (FBUF *)malloc(sizeof(FBUF))))
  324.         Fatal("insufficient memory");
  325.  
  326.     if (!(f2 = (FBUF *)malloc(sizeof(FBUF))))
  327.         Fatal("insufficient memory");
  328.  
  329.     if ((f1->fd = open(name1, AREAD)) < 0)
  330.         Fatal("unable to open %s", name1);
  331.  
  332.     if ((f2->fd = open(name2, AREAD)) < 0)
  333.         Fatal("unable to open %s", name2);
  334.  
  335.     f1->mptr = f1->eptr = f1->line[0].lptr = f1->buff;
  336.     f2->mptr = f2->eptr = f2->line[0].lptr = f2->buff;
  337.     HashMore(0, MAXLINES);
  338.     HashMore(1, MAXLINES);
  339. }
  340.  
  341. /*
  342.  *    good old main
  343.  */
  344.  
  345. int main(argc, argv)
  346. int    argc;
  347. char    *argv[];
  348. {
  349.     if (argc != 3)
  350.         Fatal("usage: diff file1 file2");
  351.  
  352.     Init(argv[1], argv[2]);
  353.  
  354.     while (!AtEOF())
  355.         CmpRegion();
  356.  
  357.     CloseUp();
  358.  
  359.     return (differences);
  360. }
  361.  
  362.  
  363. /*
  364.  *    END of diff.c
  365.  */
  366.